#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <cerrno>
#include <unordered_map>
#include <functional>
#include "Sock.hpp"
#include "Epoller.hpp"
#include "Log.hpp"
#include "Util.hpp"
#include "Protocol.hpp"

// 基于Reactor模式，编写一个充分读取和写入的，EPOLL(ET)的Server

class Connection;
class TcpServer;

using func_t = std::function<int(Connection *)>;
using callback_t = std::function<int (Connection *, std::string&)>;

class Connection
{
public:
    // 文件描述符
    int sock_;
    TcpServer* R_;
    // 自己的接受和发送缓冲区
    std::string inbuffer_;
    std::string outbuffer_;
    // 回调函数
    func_t recver_;
    func_t sender_;
    func_t excepter_;

public:
    Connection(int sock, TcpServer *r) : sock_(sock),R_(r)
    {
    }
    void SetRecver(func_t recver) { recver_ = recver; }
    void SetSender(func_t sender) { sender_ = sender; }
    void SetExcepter(func_t excepter) { excepter_ = excepter; }
    ~Connection() {}
};

class TcpServer
{
public:
    TcpServer(callback_t cb,int port = 8080):cb_(cb)
    {
        revs = new struct epoll_event[revs_num];
        // 网络功能
        listensock_ = Sock::Socket();
        Util::SetNonBlock(listensock_);
        Sock::Bind(listensock_, port);
        Sock::Listen(listensock_);

        // 多路转接
        epfd_ = Epoller::CreateEpoller();

        // 添加listensock到epoll
        Epoller::AddEvent(epfd_, listensock_, EPOLLIN | EPOLLET);

        // 将listensock匹配的Connection也添加到当前的unordered_map中
        Connection *conn = new Connection(listensock_, this);
        conn->SetRecver(std::bind(&TcpServer::Accepter, this, std::placeholders::_1));

        connections.insert(std::make_pair(listensock_, conn));
    }
    int Accepter(Connection *conn)
    {
        // demo - TODO
        std::string clientip;
        uint16_t clientport = 0;
        int sockfd = Sock::Accept(conn->sock_, &clientip, &clientport);
        if (sockfd < 0)
        {
            logMessage(WARNING, "accept error");
            return -1;
        }
        logMessage(DEBUG, "get a new link: %d", sockfd);
        AddConnection(sockfd, EPOLLIN | EPOLLET);
        return 0;
    }
    
    void AddConnection(int sockfd, uint32_t event)
    {
        if (event & EPOLLET)
            Util::SetNonBlock(sockfd);
        // 添加sockfd到epoll
        Epoller::AddEvent(epfd_, sockfd, event);
        // 将sockfd匹配的Connection也添加到当前的unordered_map中
        Connection *conn = new Connection(sockfd, this);

        conn->SetRecver(std::bind(&TcpServer::TcpRecver, this, std::placeholders::_1));
        conn->SetSender(std::bind(&TcpServer::TcpSender, this, std::placeholders::_1));
        conn->SetExcepter(std::bind(&TcpServer::TcpExcepter, this, std::placeholders::_1));

        connections.insert(std::make_pair(sockfd, conn));
        logMessage(DEBUG, "添加新链接到connections成功: %d", sockfd);
    }
    int TcpRecver(Connection *conn)
    {
        // XXXXXXX\3XXXXXX\3
        while (true)
        {
            char buffer[1024];
            ssize_t s = recv(conn->sock_, buffer, sizeof(buffer)-1, 0);
            if (s > 0)
            {
                buffer[s] = 0;
                conn->inbuffer_ += buffer;
            }
            else if (s == 0)
            {
                // TODO
                logMessage(DEBUG, "client quit");
            }
            else
            {
                if(errno == EINTR) continue;
                else if(errno == EAGAIN || errno == EWOULDBLOCK) break;
                else
                {
                    //出错了
                    //TODO
                }
            }
        }
        // 将本轮全部读取完毕
        std::vector<std::string> result;
        PackageSplit(conn->inbuffer_, &result);
        for(auto &message : result)
        {
            cb_(conn, message);
        }
        return 0;
    }
    int TcpSender(Connection *conn)
    {
        return 0;
    }
    int TcpExcepter(Connection *conn)
    {
        return 0;
    }
    bool IsExists(int sock)
    {
        auto iter = connections.find(sock);
        if (iter == connections.end())
            return false;
        else
            return true;
    }
    // 根据就绪事件，将事件进行事件派发
    void Dispatcher()
    {
        int n = Epoller::LoopOnce(epfd_, revs, revs_num);
        for (int i = 0; i < n; i++)
        {
            int sock = revs[i].data.fd;
            uint32_t revent = revs[i].events;
            if (revent & EPOLLIN)
            {
                if (IsExists(sock) && connections[sock]->recver_)
                    connections[sock]->recver_(connections[sock]);
            }
            if (revent & EPOLLOUT)
            {
                if (IsExists(sock) && connections[sock]->sender_)
                    connections[sock]->sender_(connections[sock]);
            }
        }
    }
    void Run()
    {
        while (true)
        {
            Dispatcher();
        }
    }
    ~TcpServer()
    {
        if (listensock_ != -1)
            close(listensock_);
        if (epfd_ != -1)
            close(epfd_);
        delete[] revs;
    }

private:
    static const int revs_num = 64;
    // 1. 网络socket
    int listensock_;
    // 2. epoll
    int epfd_;
    // 3. 将epoll和上层代码进行结合
    std::unordered_map<int, Connection *> connections;
    // 4. 就绪事件列表
    struct epoll_event *revs;
    // 5. 设置完整报文的处理方法
    callback_t cb_;
};


